/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Controller;

import RoomDTO.*;
import AccountDTO.*;
import XMLManipulator.XMLDealer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;

/**
 *
 * @author Phuong Giang
 */
public class ChatController extends HttpServlet {

    public static ArrayList<Room> roomList = new ArrayList<Room>();
    private static String path;

//    private Properties LoginController.configFile;
//    private static Timer timer;

    @Override
    public void init() throws ServletException {
        try {
            super.init();
            Properties configFile = getConfigFile();
            path = configFile.getProperty("DBfolder");
        } catch (IOException ex) {
            Logger.getLogger(ChatController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private Properties getConfigFile() throws IOException {
        Properties configFile = new Properties();
        // initialize configFile
        InputStream inputStream = getServletContext().getResourceAsStream("WEB-INF/config.properties");
        configFile = new Properties();
        configFile.load(inputStream);
        return configFile;
    }

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        try {
//            String path = LoginController.configFile.getProperty("DBfolder");

            String action = request.getParameter("btnAction");
            HttpSession session = request.getSession(true);
            // get user who send request
            Account user = (Account) session.getAttribute("USER");
            if (user == null) {
                response.sendRedirect("login.jsp");
            } else {
                if (action.equals("create")) {
                    /*
                     * create a new room and an xml file to store its info
                     */
                    String roomID = createRoom(user);
                    PrintWriter writer = response.getWriter();
                    writer.write("{\"roomID\":\"" + roomID + "\","
                            + "\"lastUpdate\":" + new Date().getTime() + "}");
                    writer.close();
                } else if (action.equals("leave")) {

                    /* get current user and
                     * remove him from the current room
                     */
                    String roomID = request.getParameter("roomID");

                    /* find and read the room XML file
                     * then get its participant list and
                     * remove current user from the list
                     * last, update participant list back to the file                 *
                     */
                    Room room = (Room) XMLDealer.Read(Room.class, path + roomID + ".xml");
                    List<Participant> participant = room.getParticipants().getParticipant();

                    for (Participant p : participant) {
                        if (p.getUsername().equals(user.getUsername())) {
                            room.getParticipants().getParticipant().remove(p);
                        }
                    }
                    // remove the room from his roomList
                    LoginController.onlineList.getAccount(user.getUsername()).removeRoom(roomID);

                    XMLDealer.Write(Room.class, path + roomID + ".xml", room);
                } else if (action.equals("join")) {

                    /*
                     * add joiners to current room
                     */
                    String roomID = request.getParameter("roomID");
                    String joiner = request.getParameter("joiner");
                    String[] joinerList = joiner.split(",");
                    // create a room if there's no roomID
                    if (roomID == null) {
                        roomID = createRoom(user);
                        //Tung
                        PrintWriter writer = response.getWriter();
                        writer.write("{\"roomID\":\"" + roomID + "\"}");
                        writer.close();
                    }
                    addJoiner(joinerList, roomID);
                } else if (action.equals("getMsg")) {
                    // user sends roomID and last update time
                    String roomID = request.getParameter("roomID");
                    String lastUpdate = request.getParameter("lastUpdate");
                    // return an xml contains message list
                    response.setContentType("text/xml");
                    writeMessage(roomID, (lastUpdate == null ? "" : lastUpdate), response.getOutputStream());
                } else if (action.equals("sendMsg")) {
                    /*
                     * user post a message in a room
                     * 1. get roomID + msg
                     * 2. find xml file
                     * 3. add message to xml msg list
                     * 4. update file xml
                     * 5. redirect to index.jsp when finished the job
                     */
                    String roomID = request.getParameter("roomID");
                    String msg = request.getParameter("msg");

                    Room room = (Room) XMLDealer.Read(Room.class, path + roomID + ".xml");
                    List<Message> msgList = room.getMessages().getMessage();

                    Message newMsg = new Message();

                    // get sender from participant list
                    List<Participant> partList = room.getParticipants().getParticipant();

                    for (Participant p : partList) {
                        if (p.getUsername().equals(user.getUsername())) {
                            newMsg.setSender(p);
                            newMsg.setSentTime(new BigInteger(new Date().getTime() + ""));
                            newMsg.setContent(msg);

                            // add newMsg to msgList
                            msgList.add(newMsg);

                            // update file XML
                            XMLDealer.Write(Room.class, path + roomID + ".xml", room);
                            break;
                        }
                    }
                } else if (action.equals("getRooms")) {
                    response.setContentType("text/xml");
                    PrintWriter out = response.getWriter();
                    out.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?><rooms>");
                    for (Room r : LoginController.onlineList.getAccount(user.getUsername()).getRoomList()) {
                        out.write("<room id=\"" + r.getRoomID() + "\"/>");
                    }
                    out.write("</rooms>");
                    out.close();
                }
            }
        } finally {
//            out.close();
        }
    }

    private void addJoiner(String[] joinerList, String roomID) {
        try {
            // get current participant list in the room
            String path = getConfigFile().getProperty("DBfolder");
            Room room = (Room) XMLDealer.Read(Room.class, path + roomID + ".xml");
            List<Participant> partList = room.getParticipants().getParticipant();
            // check joiner username
            // get joiner info from the onlineList
            // check if joiner is not in participant list
            // add joiner
            // if existed, don't add
            boolean isExisted = false;
            for (String tmp : joinerList) {
                if (!isExisted) {
                    for (Participant p : partList) {
                        if (p.getUsername().equals(tmp)) {
                            isExisted = true;
                            break;
                        }
                    }
                }
            }
            if (!isExisted) {
                for (String tmp : joinerList) {
                    for (AccountExtended p : LoginController.onlineList.getAccounts()) {
                        if (tmp.equals(p.getUsername())) {
                            Participant part = new Participant();
                            part.setUsername(p.getUsername());
                            part.setDisplayName(p.getDisplayName());
                            partList.add(part);
                            p.getRoomList().add(room);
                            break;
                        }
                    }
                }
                // update XML file
                XMLDealer.Write(Room.class, path + roomID + ".xml", room);
            }
        } catch (IOException ex) {
            Logger.getLogger(ChatController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private String createRoom(Account user) {
        try {
            /* create a new room and an xml file
             * add it to roomList
             */
            // get the current time of the system and add created Time
            Participant creator = new Participant();
            creator.setUsername(user.getUsername());
            creator.setIsCreator(Boolean.TRUE);
            creator.setDisplayName(user.getDisplayName());

            BigInteger createdTime = new BigInteger(new Date().getTime() + "");
            Room newRoom = new Room();
            newRoom.setCreatedTime(createdTime);
            BigInteger lastUpdate = new BigInteger(new Date().getTime() + "");
            newRoom.setLastUpdate(lastUpdate);
            newRoom.setRoomID(generateRoomID(creator.getUsername(), createdTime + ""));
            // add creator to participant list
            if (newRoom.getParticipants() == null) {
                newRoom.setParticipants(new Room.Participants());
            }
            newRoom.getParticipants().getParticipant().add(creator);
            if (newRoom.getMessages() == null) {
                newRoom.setMessages(new Room.Messages());
            }

            String path = getConfigFile().getProperty("DBfolder");
            XMLDealer.Write(Room.class, path + newRoom.getRoomID() + ".xml", newRoom);

            roomList.add(newRoom);
            // add new room to room list of creator
            LoginController.onlineList.getAccount(user.getUsername()).getRoomList().add(newRoom);

            //Tung
            return newRoom.getRoomID();
        } catch (IOException ex) {
            Logger.getLogger(ChatController.class.getName()).log(Level.SEVERE, null, ex);
            return "";
        } finally {
        }      
    }

    private String generateRoomID(String creator, String createdTime) {
        return creator + createdTime;
    }

    private void writeMessage(String roomID, String lastUpdate, OutputStream output) {
        try {
            //        try {
            String path = getConfigFile().getProperty("DBfolder");
            // load room and its messages
            Room room = (Room) XMLDealer.Read(Room.class, path + roomID + ".xml");
            List<Message> msgList = room.getMessages().getMessage();
            // if lastUpdate = "", return all msg
            // else, return new msg only
            if (!lastUpdate.equals("")) {
                // remove old messages
                for (int i = 0; i < msgList.size(); i++) {
                    Message msg = msgList.get(i);
                    long sentTime = Long.parseLong(msg.getSentTime().toString());
                    long updateTime = Long.parseLong(lastUpdate);
                    if (sentTime < updateTime) {
                        msgList.remove(msg);
                        --i;
                    }
                }
            }
            room.setLastUpdate(new BigInteger(new Date().getTime() + ""));
            // send result with only new msg to output stream of response
            XMLDealer.Write(Room.class, output, room);
        } catch (IOException ex) {
            Logger.getLogger(ChatController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException,
            IOException {
        processRequest(request, response);


    }

    /**
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException,
            IOException {
        processRequest(request, response);


    }

    /**
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";

    }// </editor-fold>
}
